package RayTracing;



public class Camera {

	//########################## Global Variables ###################################

	//Camera Origin
	public double[] position = new double[3];
	
	
	//Camera Coordinate System
	public double[] upVector = new double[3];  
	public double[] rightVector = new double[3];  
	public double[] directionVector = new double[3]; 
	
	//Camera Plane
	public double wRatio; // Width Ratio
	public double hRatio; // Height Ratio

	public double screenDistance;
	public double screenWidth;
	public double screenHeight;
	
	public double[] orgP0 = new double[3]; // Lower Left position of Image
	public double[] P = new double[3]; // Center of plane

	

	//########################## Constructors ###################################
	public Camera() {
		if (RayTracer.SHOW_LOG){ System.out.println("In Camera Empty Constructor");}
	}
	
	public Camera(String[] args, int[] imageDimesnsion) {
		
		if (RayTracer.SHOW_LOG){ System.out.println("In Camera Constructor");}

		
		double[] lookAtPosition = new double[3];  
		lookAtPosition[0] = Double.parseDouble(args[3]);
		lookAtPosition[1] = Double.parseDouble(args[4]);
		lookAtPosition[2] = Double.parseDouble(args[5]);
		
		double[] orgUpVector= new double[3];
		orgUpVector[0] = Double.parseDouble(args[6]);
		orgUpVector[1] = Double.parseDouble(args[7]);
		orgUpVector[2] = Double.parseDouble(args[8]);
		

		//### Setes Origin
		position[0] = Double.parseDouble(args[0]);
		position[1] = Double.parseDouble(args[1]);
		position[2] = Double.parseDouble(args[2]);
		
		//###Calculate Coordinate System
		directionVector = Vector.createNormalizedVectorv(position, lookAtPosition);
		rightVector = Vector.getPerpendicularVector(orgUpVector, directionVector ); 
		upVector = Vector.getPerpendicularVector(rightVector, directionVector );
		//upVector = Vector.createNormalizedVectorv(position, orgUpVector);

		
		//##### Calculate Plane
		screenDistance = Double.parseDouble(args[9]);
		screenWidth = Double.parseDouble(args[10]);
		
		// screenHeight = screeneWidth *imgHeight / imageWidth
		screenHeight = (double) ((screenWidth * imageDimesnsion[1]) /  imageDimesnsion[0]);
		
		SetScreenPlane(imageDimesnsion);
		
		
	}
	
	
	//########################## Camera Functions ###################################
	private void SetScreenPlane(int[] imageDimesnsion) {
		// Sets the plane in XYZ coordinates
		
		
		//          Width Ratio = screenWidth / imgWidth
		wRatio = screenWidth / imageDimesnsion[0]; 
		//      height Ratio = screenHeight / imgHeight
		hRatio = screenHeight / imageDimesnsion[1]; 
		
		
		//			P = camPosition + Vz * camDistance
		double[] distScalar = Vector.multiplyVectorbyScalar(directionVector, screenDistance);
		P = Vector.computeVectorAddition(position, distScalar);
		
		
		//			P0 = P - Vz * screenWidth/2 - Vy * screenHeight/2
		double[] heightFromCenter = Vector.multiplyVectorbyScalar(upVector, screenHeight/2);
		double[] widthFromCenter = Vector.multiplyVectorbyScalar(rightVector, screenWidth/2);
		orgP0 = Vector.computeVectorSubstraction(Vector.computeVectorSubstraction(P, widthFromCenter), heightFromCenter);			
		
	}
	
	public double[] IJ2los(int i, int j){
		// Retrieves XYZ coordinate of image IJ
		
		double[] vzAdd = Vector.multiplyVectorbyScalar(upVector, (double) j * hRatio);
		double[] vyAdd = Vector.multiplyVectorbyScalar(rightVector, (double) i * wRatio);
		
		double[] point = Vector.computeVectorAddition(Vector.computeVectorAddition(vzAdd, vyAdd), orgP0);
		return Vector.createNormalizedVectorv(position, point);
	}
	
	public double[] addI(double[] los){
		return Vector.computeVectorAddition(Vector.multiplyVectorbyScalar(rightVector, wRatio), los);
	}
	
	public double[] addJ(double[] los){
		return Vector.computeVectorAddition(Vector.multiplyVectorbyScalar(upVector, hRatio), los);
	}
	
	
	
	//########################## Getters and Setters ###################################
	public double[] getRightVector() {
		return rightVector;
	}


	public void setRightVector(double[] rightVector) {
		this.rightVector = rightVector;
	}


	public double[] getDirectionVector() {
		return directionVector;
	}


	public void setDirectionVector(double[] directionVector) {
		this.directionVector = directionVector;
	}


	public double getwRatio() {
		return wRatio;
	}


	public void setwRatio(double wRatio) {
		this.wRatio = wRatio;
	}


	public double gethRatio() {
		return hRatio;
	}


	public void sethRatio(double hRatio) {
		this.hRatio = hRatio;
	}


	public double getScreenHeight() {
		return screenHeight;
	}


	public void setScreenHeight(double screenHeight) {
		this.screenHeight = screenHeight;
	}


	public double[] getOrgP0() {
		return orgP0;
	}


	public void setOrgP0(double[] orgP0) {
		this.orgP0 = orgP0;
	}


	public double[] getP() {
		return P;
	}


	public void setP(double[] p) {
		P = p;
	}


	public double[] getPosition() {
		return position;
	}


	public void setPosition(double[] position) {
		this.position = position;
	}



	public double[] getUpVector() {
		return upVector;
	}


	public void setUpVector(double[] upVector) {
		this.upVector = upVector;
	}
	


	public double getScreenDistance() {
		return screenDistance;
	}


	public void setScreenDistance(double screenDistance) {
		this.screenDistance = screenDistance;
	}


	public double getScreenWidth() {
		return screenWidth;
	}


	public void setScreenWidth(double screenWidth) {
		this.screenWidth = screenWidth;
	}
	
	

}
